package com.kotlin.lib


// 协变
interface Producer<out T> {
    fun product(): T
}

class FruitProducer : Producer<Fruit> {
    override fun product(): Fruit {
        println("FruitProducer")
        return Fruit()
    }
}

class AppleProducer : Producer<Apple> {
    override fun product(): Apple {
        println("producer apple")
        return Apple()
    }
}

class ApplePearProducer : Producer<ApplePear> {
    override fun product(): ApplePear {
        println("producer applePear")
        return ApplePear()
    }
}

fun main() {
    //协变out利用多态特性。在只读的（函数返回处）地方，拿到一个子类，而引用处是一个父类型。所以没有问题
    var producer1: Producer<Fruit> = FruitProducer()
    var producer2: Producer<Fruit> = AppleProducer()
    var producer3: Producer<Fruit> = ApplePearProducer()
    producer1 = producer2

    //逆变 in同样是多态的应用。在使用方（函数入参）定义的是父类型的引用，而实际是子类型的实例
    var consumer: Consumer<ApplePear> = Human<Fruit>()
    var consumer2: Consumer<ApplePear> = Boy<Apple>()
    var consumer3: Consumer<ApplePear> = Girl<ApplePear>()
//consumer2.consume(Apple())
    consumer.consume(ApplePear())

    val sourceArray = arrayOf(1, 2, 3, 4)
    val destArray: Array<Any> = Array(4) { "hello$it" }

    destArray.forEach { println(it) }
    println("-----------------")
    copy(sourceArray, destArray)
    destArray.forEach { println(it) }
}

//逆变
interface Consumer<in T> {
    fun consume(t: T)
}

class Human<Fruit> : Consumer<com.kotlin.lib.Fruit> {
    override fun consume(t: com.kotlin.lib.Fruit) {
        println("consume fruit")
    }
}

class Boy<Apple> : Consumer<com.kotlin.lib.Apple> {
    override fun consume(t: com.kotlin.lib.Apple) {
        println("boy consume apple")
    }
}

class Girl<ApplePear> : Consumer<com.kotlin.lib.ApplePear> {
    override fun consume(t: com.kotlin.lib.ApplePear) {
        println("girl consume apple pear")
    }
}

//使用处协变（又称类型投影投影）
fun copy(source: Array<out Any>, dest: Array<in Any>) {
    assert(source.size == dest.size)

    for (i in source.indices) {
        dest[i] = source[i]
    }

}